package com.ts.api.module.api.service.impl;

import com.gitee.apanlh.util.base.IteratorUtils;
import com.gitee.apanlh.util.valid.Assert;
import com.gitee.apanlh.util.valid.ValidParam;
import com.gitee.apanlh.web.model.vo.RequestVO;
import com.ts.api.common.constant.api.ApiBizTypeEnum;
import com.ts.api.common.constant.api.ApiEnum;
import com.ts.api.common.constant.api.ApiVersionModeEnum;
import com.ts.api.common.redis.ApiMatchRedisKey;
import com.ts.api.common.util.H5DomainUrlUtils;
import com.ts.api.exp.ApiMsgException;
import com.ts.api.module.api.convert.core.entity.ApiBizStatus;
import com.ts.api.module.api.convert.platform.context.ApiPlatformConvertContext;
import com.ts.api.module.api.convert.platform.handler.ApiPlatformPhoneMd5ConvertHandler;
import com.ts.api.module.api.convert.receive.entity.ApiReceiveApply;
import com.ts.api.module.api.convert.receive.entity.ApiReceivePhoneMd5DataExchange;
import com.ts.api.module.api.convert.receive.handler.DelegatingApiReceivePhoneMd5ConvertHandler;
import com.ts.api.module.api.entity.ApiUserRequest;
import com.ts.api.module.api.entity.bo.ApiBizMatchBO;
import com.ts.api.module.api.entity.bo.ApiDataExchangeBO;
import com.ts.api.module.api.entity.bo.ApiParameterBO;
import com.ts.api.module.api.entity.bo.ApiPreRequiredBO;
import com.ts.api.module.api.entity.bo.ApiRequiredFlowBO;
import com.ts.api.module.api.entity.po.ApiKeyPO;
import com.ts.api.module.api.entity.vo.ReqApiParameterVO;
import com.ts.api.module.api.handler.ApiReceiveHandler;
import com.ts.api.module.api.service.ApiBizApplyNoticeService;
import com.ts.api.module.api.service.ApiBizApplyService;
import com.ts.api.module.api.service.ApiBizDataExchangeService;
import com.ts.api.module.api.service.ApiBizRequiredService;
import com.ts.api.module.api.service.ApiReceiveV2Service;
import com.ts.api.module.api.service.ApiUserRegister;
import com.ts.api.module.product.entity.po.ProductApplyFlowPO;
import com.ts.api.module.product.entity.po.ProductPO;
import com.ts.api.module.product.entity.po.ProductPlanPO;
import com.ts.api.module.product.service.ProductPlanService;
import com.ts.api.module.product.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;

@Service
public class ApiReceiveV2ServiceImpl implements ApiReceiveV2Service {

    @Autowired
    private ApiReceiveHandler apiReceiveHandler;
    @Autowired
    private DelegatingApiReceivePhoneMd5ConvertHandler delegatingApiReceivePhoneMd5ConvertHandler;
    @Autowired
    private ApiBizDataExchangeService apiBizDataExchangeService;
    @Autowired
    private ApiBizRequiredService apiBizRequiredService;
    @Autowired
    private ApiBizApplyService apiBizApplyService;
    @Autowired
    private ApiUserRegister apiUserRegister;
    @Autowired
    private ProductPlanService productPlanService;
    @Autowired
    private ApiBizApplyNoticeService apiBizApplyNoticeService;
    @Autowired
    private ProductService productService;
    @Autowired
    private ApiPlatformConvertContext apiPlatformConvertContext;

    @Override
    public Map<String, Object> dataExchange(ApiKeyPO apiKeyPO, RequestVO requestVO) {
        try {
            //  1.解析撞库请求实体
            ReqApiParameterVO reqApiParameterVO = apiReceiveHandler.handleDataExchangeRequest(apiKeyPO, requestVO);

            //  验证版本
            if (!ApiVersionModeEnum.MD5.hasVersionMode(apiKeyPO.getApiVersionMode())) {
                throw new ApiMsgException(ApiEnum.API_VERSION_MODE_ERROR);
            }

            //  2.撞库前置校验-创建正常计划类型匹配（机构、平台）
            ApiBizMatchBO normalPlan = ApiBizMatchBO.createNormalPlan(true);
            ApiPreRequiredBO apiPreRequiredBO = ApiPreRequiredBO.create(reqApiParameterVO, ApiBizTypeEnum.DATA_EXCHANGE, null, normalPlan);
            ApiParameterBO apiParameterBO = apiBizRequiredService.preRequiredParam(apiPreRequiredBO);

            //  3.执行撞库
            ApiDataExchangeBO apiDataExchangeBO = apiBizDataExchangeService.dataExchange(apiParameterBO);

            //  4.创建返回实体
            ApiReceivePhoneMd5DataExchange messageV2 = ApiReceivePhoneMd5DataExchange.create(apiDataExchangeBO, apiKeyPO);

            //  5.返回响应
            return delegatingApiReceivePhoneMd5ConvertHandler.respDataExchange(messageV2);
        } catch (Exception e) {
            throw apiReceiveHandler.dataExchangeWrapApiException(e);
        }
    }

    @Override
    public Map<String, Object> apply(ApiKeyPO apiKeyPO, RequestVO requestVO) {
        try {
            //  1.解析进件请求实体
            ReqApiParameterVO reqApiParameterVO = apiReceiveHandler.handleApplyRequest(apiKeyPO, requestVO);

            //  验证版本
            if (!ApiVersionModeEnum.MD5.hasVersionMode(apiKeyPO.getApiVersionMode())) {
                throw new ApiMsgException(ApiEnum.API_VERSION_MODE_ERROR);
            }

            //  2.获取参数
            ApiUserRequest apiUserRequest = reqApiParameterVO.getApiUserRequest();
            String phoneMd5 = apiUserRequest.getPhoneMd5();

            //  3.查询是否渠道存在该流程
            ApiRequiredFlowBO apiRequiredFlowBO = ApiRequiredFlowBO.createByApiClientId(phoneMd5, apiKeyPO.getApiClientId());
            ProductApplyFlowPO productApplyFlowPO = apiBizRequiredService.requiredSucDataExchangeFlow(apiRequiredFlowBO);
            Assert.isNotNullThrows(productApplyFlowPO, new ApiMsgException(ApiEnum.API_APPLY_FLOW_ERROR));

            //  4.进件前置参数验证-正常计划类型匹配（机构、平台）
            ApiBizMatchBO normalPlan = ApiBizMatchBO.createNormalPlan(true);
            ApiPreRequiredBO apiPreRequiredBO = ApiPreRequiredBO.create(reqApiParameterVO, ApiBizTypeEnum.APPLY, null, normalPlan);
            ApiParameterBO apiParameterBO = apiBizRequiredService.preRequiredParam(apiPreRequiredBO);

            //  5.进件通知模式-下游回调授权页面（对方页面）-> 查询redis中是否存在平台下游分发 -> 存在则进件下游平台渠道
            if (ValidParam.isNotEmpty(apiKeyPO.getApiPullApplyNotifyUrl())) {
                String applyNoticeFlowKey = ApiMatchRedisKey.getApplyNoticeFlowKey(apiKeyPO.getApiClientId(), productApplyFlowPO.getLoanProductPlanId(), phoneMd5);
                //  有可能上游超时进件，无法获取到key
                if (ValidParam.isNull(ApiMatchRedisKey.API_CHANNEL_APPLY_NOTICE_FLOW.get(applyNoticeFlowKey))) {
                    throw new ApiMsgException(ApiEnum.API_NOTICE_APPLY_TIMEOUT);
                }
                apiBizApplyService.apply(apiUserRequest, apiParameterBO, productApplyFlowPO);
            } else {
                // 撞库进件模式-注册用户
                apiUserRegister.applyUserRegister(apiParameterBO, productApplyFlowPO);
            }

            //  6.获取计划信息
            ProductPlanPO productPlanPO = productPlanService.get(productApplyFlowPO.getLoanProductPlanId());
            String callUrl = H5DomainUrlUtils.createH5CallUrl(productApplyFlowPO.getPhoneMd5(), productApplyFlowPO.getApiClientId());

            //  7.返回实体
            ApiReceiveApply apiReceiveApply = new ApiReceiveApply();
            apiReceiveApply.setApiClientId(productApplyFlowPO.getApiClientId());
            apiReceiveApply.setOrgName(productPlanPO.getName());
            apiReceiveApply.setDisplayName(productPlanPO.getDisplayName());
            apiReceiveApply.setPrice(productPlanPO.getPrice());
            apiReceiveApply.setPhone(apiUserRequest.getPhone());
            apiReceiveApply.setPhoneMd5(productApplyFlowPO.getPhoneMd5());
            apiReceiveApply.setCallUrl(callUrl);
            apiReceiveApply.setProductApplyFlowPO(productApplyFlowPO);
            apiReceiveApply.setBizMsg(ApiEnum.API_SIGN_SUC.getMsg());
            apiReceiveApply.setBizCode(ApiEnum.API_SIGN_SUC.getCode());

            //  8.返回消息
            return delegatingApiReceivePhoneMd5ConvertHandler.respApply(apiReceiveApply);
        } catch (Exception e) {
            throw apiReceiveHandler.applyWrapApiException(e);
        }
    }

    @Override
    public Map<String, Object> applyCallbackNotice(Long productId, RequestVO requestVO) {
        ProductPO productPO;
        ProductPlanPO productPlanPO = null;

        try {
            //  获取固定主体机构
            productPO = productService.get(productId);
            Assert.isNotNullThrows(productPO, new ApiMsgException(ApiEnum.API_NULL_FAIL.format("org", "主体id不可为null")));

            //  获取该主体下的计划
            List<ProductPlanPO> listPlan = productPlanService.listByProductId(productId);
            Assert.isNotEmptyThrows(listPlan, new ApiMsgException(ApiEnum.API_NULL_FAIL.format("plan", "计划id不可为null")));

            //  获取第一个计划
            productPlanPO = IteratorUtils.getFirst(listPlan);
            if (productPlanPO == null) {
                throw new ApiMsgException(ApiEnum.API_RECEIVE_PLAN_MISS);
            }

            //  执行通知流程
            return apiBizApplyNoticeService.applyAcceptNotice(requestVO, productPO, productPlanPO);
        } catch (Exception e) {
            ApiMsgException apiMsgException;
            if (e instanceof ApiMsgException) {
                apiMsgException = ((ApiMsgException) e);
            } else {
                apiMsgException = new ApiMsgException(ApiEnum.API_EXP_ERROR, e);
            }

            ApiBizStatus failMessage = ApiBizStatus.fail(apiMsgException.getApiMsg(), apiMsgException.getApiCode());
            apiMsgException.setReceiveMode(true);

            if (productPlanPO == null) {
                throw new ApiMsgException(ApiEnum.API_RECEIVE_PLAN_MISS);
            }

            //  获取对方接入-平台上下文
            ApiPlatformPhoneMd5ConvertHandler platFrom = apiPlatformConvertContext.getPlatformPhoneMd5(productPlanPO);
            Map<String, Object> result = platFrom.respApplyNotice(failMessage);
            apiMsgException.setReceiveData(result);
            throw apiMsgException;
        }
    }
}
